/*
 * Hunt the ball for Ping-Pong Board from FRANZIS / conrad.de
 *
 *
 * Ver.     Date         Author           Comments
 * -------  ----------   --------------   ------------------------------
 * 1.00	    07.02.2010   Piotr Platek     initial
 *
 *
 * Feel free to provide me any feedback 
 ***************************************************************************
 **
 **  This program is free software; you can redistribute it and/or
 **  modify it under the terms of the GNU General Public License
 **  as published by the Free Software Foundation; either version 2
 **  of the License, or (at your option) any later version.
 **
 **  This program is distributed in the hope that it will be useful,
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 **  GNU General Public License for more details.
 **
 **  You should have received a copy of the GNU General Public License
 **  along with this program; if not, write to the Free Software Foundation, 
 **  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 ***************************************************************************
 */


#include "main.h"


void expload(BallType B)
{
/* Animate an explosion of a ball 
 B: position of the ball to "explode"
*/

	uint8_t i, x1, x2, x3, x4, y1, y2, y3, y4;


	for (i=0; i<3; i++)
	{	
		ClearPixel(B.x, B.y);
		x1 = B.x-1 <= 0 ? 0 : B.x-1;
		y1 = B.y;
		x2 = B.x+1 >= SWIDTH-1? SWIDTH-1 : B.x+1;
		y2 = B.y;
		x3 = B.x;
		y3 = B.y-1 <= 0 ? 0 : B.y-1;
		x4 = B.x;
		y4 = B.y+1 >= SHEIGHT-1? SHEIGHT-1 : B.y+1;
		SetPixel(x1,y1);
		SetPixel(x2,y2);
		SetPixel(x3,y3);
		SetPixel(x4,y4);
	
		_delay_ms(70);
	
		ClearPixel(x1,y1);
		ClearPixel(x2,y2);
		ClearPixel(x3,y3);
		ClearPixel(x4,y4);
	
		x1 = B.x-1 <= 0 ? 0 : B.x-1;
		y1 = B.y-1 <= 0 ? 0 : B.y-1;
		x2 = B.x-1 <= 0 ? 0 : B.x-1;
		y2 = B.y+1 >= SHEIGHT-1? SHEIGHT-1 : B.y+1;
		x3 = B.x+1 >= SWIDTH-1? SWIDTH-1 : B.x+1;
		y3 = B.y-1 <= 0 ? 0 : B.y-1;
		x4 = B.x+1 >= SWIDTH-1? SWIDTH-1 : B.x+1;
		y4 = B.y+1 >= SHEIGHT-1? SHEIGHT-1 : B.y+1;
		SetPixel(x1,y1);
		SetPixel(x2,y2);
		SetPixel(x3,y3);
		SetPixel(x4,y4);
		SetPixel(B.x, B.y);
		
		_delay_ms(70);

		ClearPixel(x1,y1);
		ClearPixel(x2,y2);
		ClearPixel(x3,y3);
		ClearPixel(x4,y4);
	}
}

void border()
{
/* Draw a border around the board
   The border will not be crossealble for the ball
*/

	for (int i=1; i < SWIDTH-1; gLEDs[i++]=0b1000000001)
	gLEDs[0] = 0b1111111111;
	gLEDs[SWIDTH-1] = 0b1111111111;
}

void expload_board()
{
/*  Just a animation of the screen after falling outside the board
*/
	LedCLS();
	int8_t max = SWIDTH-1;
	int8_t mix = 0;
	int8_t may = SHEIGHT-1;
	int8_t miy = 0;
	int8_t x,y, cx;

	#define SNAKED 20				// delay of the FX drawing

	for (cx=0; cx<05; cx++)
	{
		for (x=mix; x<=max; x++)
		{ 
			_delay_ms(SNAKED);
			SetPixel(x,miy);
		}
		miy +=1;
		for (y=miy; y<=may; y++)
		{ 
			_delay_ms(SNAKED);
			SetPixel(max,y);
		}
		max -=1;
		for (x=max; x>=mix; x--)
		{ 
			_delay_ms(SNAKED);
			SetPixel(x,may);
		}
		may -=1;
		for (y=may; y>=miy; y--)
		{ 
			_delay_ms(SNAKED);
			SetPixel(mix,y);
		}
		mix +=1;
	}
	_delay_ms(1000);
	LedCLS();
}

int main(void)
{
  BallType BallPos;			// Position of the Ball
  BallType BallTmp;			// New tmp position of the Ball
  BallType HuntPos;			// Position of a ball to catch
  uint8_t out_of_board;		// flag outside of the board

  int16_t AccelMax;			// maximal value of the current accelometer sensor in x and y axis
  uint8_t buffor[10] = "";	// buffor for text display & manipulation
	
  uint16_t HuntCounter = 0;	// number of catched ball

  cli();

#ifdef DEBUGON
	USART_Init();
#endif

  DDRC = 0xFF;   // port B, C, D as Output
  DDRB = 0xFF;   // TWI/C2I will be set by nunchuckInit/TWI funnctions
  DDRD = 0xFF;

  /* initialize timers */
  TCCR0 |= _BV(CS01) | _BV(CS00); // clk prescale (clk/64)
  TIMSK |= _BV(TOIE0); 			// enable timer/counter0 overflow interrupt 
  TCNT0 = 0;           			// reset the timer

  sei();


  nunchuckInit(); 				// initialize nunchuck
  _delay_ms(100); 				// wait a bit for nunchuck gets ready

  HuntPos.x = 1;
  HuntPos.y = 1;
  BallPos.x = 5;  				// initial position of the player
  BallPos.y = 5;
  SetPixel(BallPos.x, BallPos.y);	// paint the player


  nunchuckRead(); 				// read the data from nunchuck
  srandom((accelX*accelY)/accelZ);// in order to start/seed the random generator
	
  while(1)
  {
	border();
	while(gametime)
	{
		nunchuckRead(); // read data from nunchuck
//		sprintf(buffor, "%d,%d,%d,%d,%d,%d,%d\n\r",accelX, accelX, accelX, joyX, joyY, butC, butZ);
//		sprintf(buffor, "%d,%d,%d,%d\r\n", accelX, accelY, accelZ, sensors[2]);
//		sprintf(buffor, "%d,%d,%d\r\n", accelX, accelY, accelZ);
//		sprintf(buffor, "%d,%d,%d\r\n", sensors[2], sensors[3], sensors[4]);
//		rsprint(buffor);

		if ( !BallDelay ) // Check if the delay for next ball point has elapsed
		{
		   	// Restore ball's delay
			BallDelay = BallSpeed;
			ClearPixel(BallPos.x, BallPos.y);		// clear pixel at the old ball position
													// calculate new position
			BallTmp = BallPos;
			if (accelX < -4) BallTmp.x -= 1;	    // in case of small movement keep the same position
			if (accelX >  4) BallTmp.x += 1;
			if (accelY < -4) BallTmp.y -= 1;
			if (accelY >  4) BallTmp.y += 1;

													// check the position to stay in on the screen
			out_of_board = 0;						// not yet
			if (BallTmp.x > SWIDTH-2)
			{
				if (BallTmp.x > SWIDTH-1) out_of_board = 1; 	// outside of the board
				else if (GetPixel(BallTmp.x, BallTmp.y)) BallTmp.x = SWIDTH-2; // a wall detected
			}
			if (BallTmp.x < 1) 
			{
				if (BallTmp.x < 0) out_of_board = 1; 			// outside of the board
				else if (GetPixel(BallTmp.x, BallTmp.y)) BallTmp.x = 1; // a wall detected
			}
			if (BallTmp.y > SHEIGHT-2) 
			{
				if (BallTmp.y > SHEIGHT-1) out_of_board = 1; 	// outside of the board
				else if (GetPixel(BallTmp.x, BallTmp.y)) BallTmp.y = SHEIGHT-2; // a wall detected
			}
			if (BallTmp.y < 1)
			{
				if (BallTmp.y < 0) out_of_board = 1; 			// outside of the board
				else if (GetPixel(BallTmp.x, BallTmp.y)) BallTmp.y = 1; // a wall detected
			}

			if (out_of_board)
			{
				if (HuntCounter) HuntCounter--;			// being outside the board decreases hunts
				expload_board();						// some FX 
				border();								// new border
				BallPos.x = 5;
				BallPos.y = 5;
				HuntPos.x = 1+ abs(random()) / (RAND_MAX / (SWIDTH-2));	// random position
				HuntPos.y = 1+ abs(random()) / (RAND_MAX / (SHEIGHT-2));
				SetPixel(HuntPos.x,HuntPos.y);							// paint a new ball to be hunted
				SetPixel(BallPos.x, BallPos.y);							// draw ball at new position
				huntdelay = HUNTDELAYS;									// again start the hunt timer 
			}
			else
			{
				BallPos = BallTmp;		
				// calculate the maximum accelerometer value
				AccelMax = abs(abs(accelX) > abs(accelY) ? accelX : accelY);
				BallSpeed =  120;						// initial delay 
				if ( AccelMax > 20 ) BallSpeed =  80;	// decrease delay according to the angle
				if ( AccelMax > 45 ) BallSpeed =  60;
				if ( AccelMax > 70 ) BallSpeed =  30;

				if (!(huntdelay)) 						// if the time for a single hunt has passed
				{										// calculate a new position for a ball to be hunted
					ClearPixel(HuntPos.x,HuntPos.y);	// clear not cached ball
					HuntPos.x = 1+abs(random()) / (RAND_MAX / (SWIDTH-2));	// random position
					HuntPos.y = 1+abs(random()) / (RAND_MAX / (SHEIGHT-2));
					SetPixel(HuntPos.x,HuntPos.y);		// paint a new ball to be hunted
					huntdelay = HUNTDELAYS;				// again start the hunt timer 
				}
				if (!(huntblink))						// small counter to blink the hunted ball
				{
					XorPixel(HuntPos.x,HuntPos.y);		// inverse curent ball status
					huntblink = HUNTBLINKS;				// restart timer
				}
	
				SetPixel(BallPos.x, BallPos.y);			// draw ball at new position
	
				// check if player has caught/hunted the ball
				if ( (BallPos.x == HuntPos.x) && (BallPos.y == HuntPos.y))
				{
					expload(BallPos);	// animate explosion
					HuntCounter++;		// increase number of hunted balls
					huntdelay=0;		// start a new hunt in next loop iteration by setting hunt timer to 0 
				}
			}
		}
		_delay_ms(100);				// wait a bit 
	}

	// the time for one level has passed
	LedCLS();								// clear screen
	sprintf((char *)buffor, "%d", HuntCounter);		// display numer of hunted balls
	LedPrint(buffor, 2,2);

	while (butC)							// wait until button C is pressed
	{
		nunchuckRead(); 					// update button C status
		_delay_ms(100);
	}

	LedCLS();								// clear screen and start the gaim again
	HuntCounter = 0;
	gametime = GAMETIMES;

  }
	return 0;
}
